'''
KML View classes 

Created on Sep 28, 2010

@author: morgan
'''
from __xml__ import createElement
from base import KMLObject, Coordinate
from time import TimeStamp
from enum import altitudeMode

__all__ = ['AbstractView', 'View', 'Camera', 'LookAt']

class AbstractView(KMLObject):
    def __init__(self, id="", timestamp=None):
        KMLObject.__init__(self, id=id)
        self._timestamp = None
 
    def _setTimeStamp(self, value):
        if not isinstance(value, TimeStamp):
            raise ValueError("Expected value to be a kml.TimeStamp instance.")
        else:
            self._timestamp = value
    
    def _getTimeStamp(self):
        return self._timestamp
    
    TimeStamp = property(_getTimeStamp, _setTimeStamp) 
    
class View(AbstractView, Coordinate):
    def __init__(self, id="", timestamp=None, heading=0, tilt=0, **kwds):
        AbstractView.__init__(self, id="", timestamp=timestamp)
        Coordinate.__init__(self, **kwds)
        self.heading = heading
        self.tilt = tilt
        self._altMode = altitudeMode()

    @property
    def heading(self):
        return self._heading
    
    @heading.setter
    def heading(self, value):
        if type(value) not in [int, float]:
            raise TypeError("Value is expected to be an int or a float.")
        elif value < 0 or value > 360:
            raise ValueError("Expecting value to be in the range of -180..+180.")
        else:
            self._heading = float(value)
            
    @property
    def tilt(self):
        return self._tilt
    
    @tilt.setter
    def tilt(self, value):
        if type(value) not in [int, float]:
            raise TypeError("Value is expected to be an int or a float.")
        elif value < 0 or value > 180:
            raise ValueError("Expecting value to be in the range of 0..180.")
        else:
            self._tilt = float(value)
        
    def _setAltitudeMode(self, value):
        if type(value) != str and type(value) != altitudeMode:
            raise TypeError("Expecting value to be a str object  or an altitudeMode class object")
        if type(value) == str:
            self._altMode.actualMode = value
        else:
            self._altMode.actualMode = value.value
            
    def _getAltitudeMode(self):
        return self._altMode.actualMode
    
    def toXmlNode(self,kml):
        node = AbstractView.toXmlNode(self, kml)
        if self.latitude != 0:
            node.appendChild(createElement(kml._doc, "latitude", self.latitude))
        if self.longitude != 0:
            node.appendChild(createElement(kml._doc, "longitude", 
                                           self.longitude))
        if self.altitude != 0:
            node.appendChild(createElement(kml._doc, "altitude", self.altitude))
        if self.heading != 0:
            node.appendChild(createElement(kml._doc, "heading", self.heading))
        if self.tilt != 0:
            node.appendChild(createElement(kml._doc, "tilt", self.tilt))
        return node
        
    def parseKMLNode(self,KMLNode):
        AbstractView.parseKMLNode(self, KMLNode)
        if KMLNode.getElementsByTagName("latitude") != []:
            self.latitude = float(KMLNode.getElementsByTagName("latitude")[0].\
                                  childNodes[0].data)
        if KMLNode.getElementsByTagName("longitude") != []:
            self.longitude = float(KMLNode.getElementsByTagName("longitude")[0].\
                                   childNodes[0].data)
        if KMLNode.getElementsByTagName("altitude") != []:
            self.altitude = float(KMLNode.getElementsByTagName("altitude")[0].\
                                  childNodes[0].data)
        if KMLNode.getElementsByTagName("heading") != []:
            self.heading = float(KMLNode.getElementsByTagName("heading")[0].\
                                 childNodes[0].data)
        if KMLNode.getElementsByTagName("tilt") != []:
            self.tilt = float(KMLNode.getElementsByTagName("tilt")[0].\
                              childNodes[0].data)
        if KMLNode.getElementsByTagName("altitudeMode") != []:
            self._altMode.parseKMLNode(KMLNode.\
                                       getElementsByTagName("altitudeMode")[0])

    altitudeMode = property(_getAltitudeMode,_setAltitudeMode)
    
class Camera(View):
    def __init__(self, id="", roll=0, **kwds):
        self.__tagName__ = "Camera"
        View.__init__(self, id=id, **kwds)
        self.roll = 0.0
    
    @property
    def roll(self):
        return self._roll
    
    @roll.setter
    def roll(self, value):
        if type(value) in [int, float]:
            if value >= -180 and value <= 180:
                self._roll = float(value)
            else:
                raise ValueError("Expecting roll to be between -180 to +180")
        else:
            raise TypeError("Expecting roll to be a float or int.")

        
    def toXmlNode(self, kml):
        node = View.toXmlNode(self, kml) 
        node.appendChild(createElement(kml._doc, "roll", self.roll))
        node.appendChild(self._altMode.toXmlNode(kml))
        return node

    def parseKMLNode(self, KMLNode):
        View.parseKMLNode(self, KMLNode)
        if KMLNode.getElementsByTagName("roll") != []:
            self.roll = float(KMLNode.getElementsByTagName("roll")[0].\
                              childNodes[0].data)

class LookAt(View):
    def __init__(self, id="", range=0, **kwds):
        self.__tagName__ = "LookAt"
        View.__init__(self, id=id, **kwds)
        self.range = range
        
    @property
    def range(self):
        return self._range
    
    @range.setter
    def range(self, value):
        if type(value) in [int, float]:
            if value >= 0:
                self._range = float(value)
            else:
                raise ValueError("Range must be a positive number.")
        else:
            raise TypeError("Range must be an int or float")

    def toXmlNode(self, kml):
        lookNode = View.toXmlNode(self, kml) 
        if self.range != 0:
            lookNode.appendChild(createElement(kml._doc, "range", self.range))
        if self.altitudeMode != 'absolute':
            lookNode.appendChild(self._altMode.toXmlNode(kml))
        return lookNode

    def parseKMLNode(self, KMLNode):
        View.parseKMLNode(self, KMLNode)
        if KMLNode.getElementsByTagName("range") != []:
            self.range = float(KMLNode.getElementsByTagName("range")[0].\
                               childNodes[0].data)
